﻿namespace CSharpCompiler
{
    using Mono.CSharp;
    using System;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using System.Collections.Specialized;
    using System.IO;
    using System.Reflection.Emit;
    using System.Runtime.CompilerServices;
    using System.Text;

    public class CodeCompiler : ICodeCompiler
    {
        private static long assemblyCounter = 0L;
        public static AppDomain targetAppDomain = AppDomain.CurrentDomain;

        public CompilerResults CompileAssemblyFromDom(CompilerParameters options, CodeCompileUnit compilationUnit)
        {
            CodeCompileUnit[] ea = new CodeCompileUnit[] { compilationUnit };
            return this.CompileAssemblyFromDomBatch(options, ea);
        }

        public CompilerResults CompileAssemblyFromDomBatch(CompilerParameters options, CodeCompileUnit[] ea)
        {
            CompilerResults results;
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }
            try
            {
                results = this.CompileFromDomBatch(options, ea);
            }
            finally
            {
                options.TempFiles.Delete();
            }
            return results;
        }

        public CompilerResults CompileAssemblyFromFile(CompilerParameters options, string fileName)
        {
            string[] fileNames = new string[] { fileName };
            return this.CompileAssemblyFromFileBatch(options, fileNames);
        }

        public CompilerResults CompileAssemblyFromFileBatch(CompilerParameters options, string[] fileNames)
        {
            CompilerSettings settings = this.ParamsToSettings(options);
            foreach (string str in fileNames)
            {
                string fullPath = Path.GetFullPath(str);
                SourceFile item = new SourceFile(str, fullPath, settings.SourceFiles.Count + 1, null);
                settings.SourceFiles.Add(item);
            }
            return this.CompileFromCompilerSettings(settings, options.GenerateInMemory);
        }

        public CompilerResults CompileAssemblyFromSource(CompilerParameters options, string source)
        {
            string[] sources = new string[] { source };
            return this.CompileAssemblyFromSourceBatch(options, sources);
        }

        public CompilerResults CompileAssemblyFromSourceBatch(CompilerParameters options, string[] sources)
        {
            CompilerSettings settings = this.ParamsToSettings(options);
            int num = 0;
            foreach (string str in sources)
            {
                <CompileAssemblyFromSourceBatch>c__AnonStorey8F storeyf = new <CompileAssemblyFromSourceBatch>c__AnonStorey8F {
                    source = str
                };
                Func<Stream> streamIfDynamicFile = new Func<Stream>(storeyf.<>m__195);
                string name = num.ToString();
                SourceFile item = new SourceFile(name, name, settings.SourceFiles.Count + 1, streamIfDynamicFile);
                settings.SourceFiles.Add(item);
                num++;
            }
            return this.CompileFromCompilerSettings(settings, options.GenerateInMemory);
        }

        private CompilerResults CompileFromCompilerSettings(CompilerSettings settings, bool generateInMemory)
        {
            CompilerResults compilerResults = new CompilerResults(new TempFileCollection(Path.GetTempPath()));
            CustomDynamicDriver driver = new CustomDynamicDriver(new CompilerContext(settings, new CustomReportPrinter(compilerResults)));
            AssemblyBuilder outAssembly = null;
            try
            {
                driver.Compile(out outAssembly, targetAppDomain, generateInMemory);
            }
            catch (Exception exception)
            {
                CompilerError error = new CompilerError {
                    IsWarning = false,
                    ErrorText = exception.Message
                };
                compilerResults.Errors.Add(error);
            }
            compilerResults.CompiledAssembly = outAssembly;
            return compilerResults;
        }

        private CompilerResults CompileFromDomBatch(CompilerParameters options, CodeCompileUnit[] ea)
        {
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }
            if (ea == null)
            {
                throw new ArgumentNullException("ea");
            }
            string[] fileNames = new string[ea.Length];
            StringCollection referencedAssemblies = options.ReferencedAssemblies;
            for (int i = 0; i < ea.Length; i++)
            {
                CodeCompileUnit compileUnit = ea[i];
                fileNames[i] = options.TempFiles.AddExtension(i + ".cs");
                FileStream stream = new FileStream(fileNames[i], FileMode.OpenOrCreate);
                StreamWriter output = new StreamWriter(stream, Encoding.UTF8);
                if (compileUnit.ReferencedAssemblies != null)
                {
                    StringEnumerator enumerator = compileUnit.ReferencedAssemblies.GetEnumerator();
                    try
                    {
                        while (enumerator.MoveNext())
                        {
                            string current = enumerator.Current;
                            if (!referencedAssemblies.Contains(current))
                            {
                                referencedAssemblies.Add(current);
                            }
                        }
                    }
                    finally
                    {
                        IDisposable disposable = enumerator as IDisposable;
                        if (disposable == null)
                        {
                        }
                        disposable.Dispose();
                    }
                }
                ((ICodeGenerator) this).GenerateCodeFromCompileUnit(compileUnit, output, new CodeGeneratorOptions());
                output.Close();
                stream.Close();
            }
            return this.CompileAssemblyFromFileBatch(options, fileNames);
        }

        private CompilerSettings ParamsToSettings(CompilerParameters parameters)
        {
            CompilerSettings settings = new CompilerSettings();
            StringEnumerator enumerator = parameters.ReferencedAssemblies.GetEnumerator();
            try
            {
                while (enumerator.MoveNext())
                {
                    string current = enumerator.Current;
                    settings.AssemblyReferences.Add(current);
                }
            }
            finally
            {
                IDisposable disposable = enumerator as IDisposable;
                if (disposable == null)
                {
                }
                disposable.Dispose();
            }
            settings.Encoding = Encoding.UTF8;
            settings.GenerateDebugInfo = parameters.IncludeDebugInformation;
            settings.MainClass = parameters.MainClass;
            settings.Platform = Platform.AnyCPU;
            settings.StdLibRuntimeVersion = RuntimeVersion.v4;
            if (parameters.GenerateExecutable)
            {
                settings.Target = Target.Exe;
                settings.TargetExt = ".exe";
            }
            else
            {
                settings.Target = Target.Library;
                settings.TargetExt = ".dll";
            }
            if (parameters.GenerateInMemory)
            {
                settings.Target = Target.Library;
            }
            if (string.IsNullOrEmpty(parameters.OutputAssembly))
            {
                parameters.OutputAssembly = settings.OutputFile = "DynamicAssembly_" + assemblyCounter + settings.TargetExt;
                assemblyCounter += 1L;
            }
            settings.OutputFile = parameters.OutputAssembly;
            settings.Version = LanguageVersion.V_6;
            settings.WarningLevel = parameters.WarningLevel;
            settings.WarningsAreErrors = parameters.TreatWarningsAsErrors;
            return settings;
        }

        [CompilerGenerated]
        private sealed class <CompileAssemblyFromSourceBatch>c__AnonStorey8F
        {
            internal string source;

            internal Stream <>m__195()
            {
                if (this.source == null)
                {
                }
                return new MemoryStream(Encoding.UTF8.GetBytes(string.Empty));
            }
        }
    }
}

